All files / Bandstand/src/app/perform/[id] page.tsx

0% Statements 0/83
0% Branches 0/1
0% Functions 0/1
0% Lines 0/83

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84                                                                                                                                                                       
export const dynamic = 'force-dynamic'

import {getServerSession} from 'next-auth'
import {notFound, redirect} from 'next/navigation'
import {authOptions} from '@/lib/auth'
import {pageSession} from '@/lib/guard'
import {followToBand} from '@/lib/band'
import {getSetlist} from '@/lib/setlists'
import Perform, {type PerformSong} from '@/components/Perform'
import {myCues} from '@/lib/cues-server'
import SaveOffline from '@/components/pwa/SaveOffline'
import {formatClock, runningOrder} from '@/lib/gig'

export const metadata = {title: 'Perform'}

export default async function PerformPage({params}: {params: {id: string}}) {
  const session = await getServerSession(authOptions)
  if (!session?.user)
    redirect(
      '/login?callbackUrl=' + encodeURIComponent(`/perform/${params.id}`),
    )
  const {user, band} = await pageSession()
  const set = await getSetlist(params.id, band.id)
  if (!set) {
    await followToBand('setlist', params.id, user.id, `/perform/${params.id}`)
    notFound()
  }
  // Every chart in the set is sent with the page, so once it has loaded the
  // whole set works without a connection.
  const {entries, sets, divided} = runningOrder(set.startTime, set.items)
  const cues = await myCues(
    user.id,
    set.items.flatMap((i) => (i.songId ? [i.songId] : [])),
  )
  const songs: PerformSong[] = []
  entries.forEach((e, at) => {
    if (e.kind !== 'SONG' || !e.item.song) return
    const s = e.item.song
    // What comes between this song and the next one: a break, or a new set
    const brk = entries.slice(at + 1).findIndex((x) => x.kind === 'SONG')
    const gap = entries.slice(at + 1, brk < 0 ? undefined : at + 1 + brk)
    const pause = gap.find((x) => x.kind === 'BREAK')
    const nextSet = gap.find((x) => x.kind === 'SET')
    songs.push({
      id: s.id,
      title: s.title,
      leadSinger: s.leadSinger,
      source: s.chartVersions[0]?.source ?? '',
      key: e.item.key,
      note: e.item.note,
      cues: cues.get(s.id) ?? [],
      set: divided
        ? {label: sets[e.set].label, n: e.n, count: sets[e.set].songs}
        : null,
      after:
        pause?.kind === 'BREAK'
          ? {
              kind: 'break',
              minutes: pause.info.minutes,
              until:
                pause.info.end != null ? formatClock(pause.info.end) : null,
            }
          : nextSet?.kind === 'SET' && brk >= 0
            ? {kind: 'set', label: nextSet.info.label}
            : null,
    })
  })
  return (
    <>
      <Perform setId={set.id} name={set.name} songs={songs} />
      {/* The setlist and its charts too, as opening the setlist does */}
      <SaveOffline
        quiet
        urls={[
          `/setlists/${set.id}`,
          ...new Set(
            set.items.flatMap((i) => (i.songId ? [`/songs/${i.songId}`] : [])),
          ),
        ]}
      />
    </>
  )
}